package com.molichuxing.services.business.service.impl;

import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.ObjectCastUtil;
import com.molichuxing.services.business.convertor.Convert;
import com.molichuxing.services.business.dto.request.create.EnterpriseScheduleCreateBizDto;
import com.molichuxing.services.business.dto.response.EnterpriseScheduleBizDto;
import com.molichuxing.services.business.service.EnterpriseScheduleBizService;
import com.molichuxing.services.exception.OrderExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.request.create.EnterpriseScheduleCarCreateDto;
import com.molichuxing.services.infrastructure.dto.response.EnterpriseCarDto;
import com.molichuxing.services.infrastructure.dto.response.EnterpriseScheduleCarCountDto;
import com.molichuxing.services.infrastructure.dto.response.EnterpriseScheduleDto;
import com.molichuxing.services.infrastructure.dto.response.OrderEnterpriseDto;
import com.molichuxing.services.infrastructure.service.EnterpriseCarService;
import com.molichuxing.services.infrastructure.service.EnterpriseScheduleCarService;
import com.molichuxing.services.infrastructure.service.EnterpriseScheduleService;
import com.molichuxing.services.infrastructure.service.OrderEnterpriseService;
import com.molichuxing.services.property.EnterpriseCarStateEnum;
import com.molichuxing.services.property.EnterpriseScheduleStateEnum;
import com.molichuxing.services.property.EnterpriseScheduleTabTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 企业订单排期服务
 *
 * @author zhaopenghui
 * @date 2020年6月4日
 */
@Service("enterpriseScheduleBizService")
public class EnterpriseScheduleBizServiceImpl implements EnterpriseScheduleBizService {
    private static final Logger logger = LoggerFactory.getLogger(EnterpriseScheduleBizServiceImpl.class);

    @Resource
    private EnterpriseScheduleService enterpriseScheduleService;

    @Resource
    private OrderEnterpriseService orderEnterpriseService;

    @Resource
    private EnterpriseCarService enterpriseCarService;

    @Resource
    private EnterpriseScheduleCarService enterpriseScheduleCarService;

    /**
     * 分页
     *
     * @param params   orderCode：订单类型
     *                 enterpriseId:企业id
     * @param pageNum  页数
     * @param pageSize 每页条数
     * @return Paged
     * @throws Exception
     */
    @Override
    public Paged<EnterpriseScheduleBizDto> getSchedulePage(Map<String, Object> params, int pageNum, int pageSize) throws Exception {
        Integer tabType = ObjectCastUtil.castInteger(params.get("tabType"));
        if (tabType != null && EnterpriseScheduleTabTypeEnum.OVERDUE_REPAYMENT.getValue() == tabType) {
            params.put("overduePayableDate", DateUtil.getDayEnd(LocalDate.now()));
            params.put("state", EnterpriseScheduleStateEnum.NO.getValue());
        }

        Paged<EnterpriseScheduleDto> schedulePage = enterpriseScheduleService.getSchedulePage(params, pageNum, pageSize);
        if (null == schedulePage) {
            return new Paged<>();
        }
        List<EnterpriseScheduleDto> dtoList = schedulePage.getList();
        if (null == dtoList || dtoList.size() < 1) {
            return new Paged<>();
        }

        List<Long> orderCodeList = new ArrayList<>();
        List<Integer> idList = new ArrayList<>();
        for (EnterpriseScheduleDto enterpriseScheduleDto : dtoList) {
            Long orderCode = enterpriseScheduleDto.getOrderCode();
            Integer scheduleId = enterpriseScheduleDto.getScheduleId();
            orderCodeList.add(orderCode);
            idList.add(scheduleId);
        }

        Map<Long, OrderEnterpriseDto> enterpriseMap = orderEnterpriseService.getEnterpriseMap(orderCodeList);
        Map<Integer, EnterpriseScheduleCarCountDto> scheduleCarMap = enterpriseScheduleCarService.getScheduleCarMap(idList);
        List<EnterpriseScheduleBizDto> pagedReturnList = Convert.toEnterpriseScheduleBizDtoList(dtoList, enterpriseMap, scheduleCarMap);
        return new Paged<>(pagedReturnList, schedulePage.getTotal(), pageSize);
    }

    /**
     * 排期信息
     *
     * @param scheduleIds 排期ids
     * @return Map
     */
    @Override
    public Map<Integer, EnterpriseScheduleBizDto> getScheduleByScheduleIds(List<Integer> scheduleIds) {
        if (null == scheduleIds || scheduleIds.size() < 1) {
            return null;
        }

        List<EnterpriseScheduleDto> scheduleByScheduleIds = enterpriseScheduleService.getScheduleByScheduleIds(scheduleIds);
        Map<Integer, EnterpriseScheduleCarCountDto> scheduleCarMap = enterpriseScheduleCarService.getScheduleCarMap(scheduleIds);
        List<EnterpriseScheduleBizDto> returnList = Convert.toEnterpriseScheduleBizDtoList(scheduleByScheduleIds, null, scheduleCarMap);
        if (null == returnList || returnList.size() < 1) {
            return null;
        }

        return returnList.stream().collect(Collectors.toMap(EnterpriseScheduleBizDto::getScheduleId, a -> a, (k1, k2) -> k1));
    }

    /**
     * 首付新增排期信息
     *
     * @param createBizDto 新增信息
     * @return boolean
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public boolean createPay(EnterpriseScheduleCreateBizDto createBizDto) {
        // 新增订单首付排期
        Integer scheduleId = enterpriseScheduleService.create(Convert.toEnterpriseScheduleCreateDto(createBizDto));
        // 查询订单车辆信息
        List<EnterpriseCarDto> enterpriseCarDtos = enterpriseCarService.getEnterpriseCar(createBizDto.getOrderCode(), EnterpriseCarStateEnum.UNPAID);
        if (enterpriseCarDtos == null || enterpriseCarDtos.isEmpty()) {
            logger.error("[createPay]首付新增排期信息失败，不存在未支付订单车辆信息");
            throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "订单新增排期失败");
        }
        List<EnterpriseScheduleCarCreateDto> createDtos = Convert.toEnterpriseScheduleCarCreateDto(scheduleId, enterpriseCarDtos, EnterpriseScheduleStateEnum.ALREADY);
        // 新增首付车辆排期
        enterpriseScheduleCarService.createBatch(createDtos);

        return true;
    }

    /**
     * 终止订单车辆排期
     *
     * @param orderCode 订单号
     * @param carId     车辆id
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public boolean modifyCarTermination(Long orderCode, Integer carId) {
        if (!enterpriseScheduleCarService.modifyTermination(carId)) {
            return false;
        }

        // 判断该订单车辆是否都不是租赁中
        List<EnterpriseCarDto> enterpriseCars = enterpriseCarService.getEnterpriseCar(orderCode, EnterpriseCarStateEnum.LEASE);
        if (enterpriseCars == null || enterpriseCars.isEmpty()) {
            // 修改订单排期信息
            if (!enterpriseScheduleService.modifyTermination(orderCode)) {
                logger.error("终止订单({})排期异常", orderCode);
                throw new RuntimeException("终止订单(" + orderCode + ")排期异常");
            }
        }

        return true;
    }

    /**
     * 获取订单排期信息
     *
     * @param orderCode 订单号
     * @return List
     */
    @Override
    public List<EnterpriseScheduleBizDto> getSchedule(Long orderCode) {
        List<EnterpriseScheduleBizDto> result = null;
        // 根据订单号，查询排期信息
        List<EnterpriseScheduleDto> scheduleDtos = enterpriseScheduleService.getSchedule(orderCode);
        if (scheduleDtos == null || scheduleDtos.isEmpty()) {
            return result;
        }
        List<Integer> scheduleIds = new ArrayList<>();
        for (EnterpriseScheduleDto scheduleDto : scheduleDtos) {
            scheduleIds.add(scheduleDto.getScheduleId());
        }
        Map<Integer, EnterpriseScheduleCarCountDto> scheduleCarMap = enterpriseScheduleCarService.getScheduleCarMap(scheduleIds);

        result = Convert.toEnterpriseScheduleBizDto(scheduleDtos, scheduleCarMap);

        return result;
    }


}
